package com.blb.day20231107login.config;

import com.blb.day20231107login.entity.ResponseResult;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.sql.DataSource;
import java.util.Arrays;

/**
 * SpringSecurity整合MVC配置，继承WebSecurityConfigurerAdapter
 * Adapter适配器设计模式，实现接口必须实现接口中所有方法
 * Adapter给接口方法默认实现，继承Adapter后只需要实现特定方法
 */
//启动注解配置授权访问
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //提供密码编码器给容器
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(WebSecurity web) throws Exception {
        //放行一些MVC的url
        web.ignoring().mvcMatchers("/upload");
    }

    //配置验证的账号密码
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //配置自定义的登录逻辑
        auth.userDetailsService(userDetailsService);
    }

    //配置访问授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置资源的授权访问
        http.authorizeRequests().antMatchers("/login","/logout").permitAll() //上面地址放行
                .anyRequest().authenticated()               //其它资源需要登录验证
                .and()
                .formLogin().loginProcessingUrl("/login")
                .successHandler(new LoginSuccessHandler())      //配置登录成功处理器
                .failureHandler((request,response,chain) -> {   //配置登录失败处理器
                    //向前端发送错误数据
                    ResponseResult.write(ResponseResult.error(401L,"账号或密码错误"),response);
                })
                .and()
                .exceptionHandling()
                    .authenticationEntryPoint((request,response,chain) -> {   //配置权限认证失败处理器
                        //向前端发送错误数据
                        ResponseResult.write(ResponseResult.error(403L,"用户没有权限"),response);
                    })
                .and()
                .logout()
                .logoutSuccessHandler((request,response,chain) -> {   //配置注销成功处理器
                    //向前端发送数据
                    ResponseResult.write(ResponseResult.ok("注销成功"),response);
                })
                .clearAuthentication(true)      //清除服务器验证信息
                .and()
                .csrf().disable()               //停止csrf攻击保护，方便测试，上线再开启
                .sessionManagement()            //session管理，不保存用户状态
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .cors()
                //配置跨域
                .configurationSource(corsConfigurationSource())
                .and()
                //在过滤器链末尾添加自定义验证过滤器
                .addFilter(new TokenAuthenticationFilter(authenticationManager()))
        ;
    }


    /**
     * 跨域配置对象
     * @return
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        //配置允许访问的服务器域名
        configuration.setAllowedOrigins(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

}
